import re
from typing import *
from dataclasses import dataclass


@dataclass(order=True)
class Word:
    def __str__(self):
        raise Exception("为了防止把 Word 直接放入翻译结果，Word 不能直接转换成字符串！需要转换成字符串可以直接调用 Word.str 方法")

    def str(self):
        return super().__str__()

    pass


@dataclass(order=True)
class Macro(Word):
    name: str
    obj: str
    args: List[Union[str, 'Code']]


@dataclass(order=True)
class Memory(Word):
    block: str
    offset: Union[str, int]


@dataclass(order=True)
class Operation(Word):
    name: str


@dataclass(order=True)
class BinaryOperation(Operation):
    left: str
    right: str


@dataclass(order=True)
class UnaryOperation(Operation):
    value: str


@dataclass(order=True)
class Sensor(Word):
    unit: str
    value: str


@dataclass(order=True)
class Value(Word):
    value: str


@dataclass(order=True)
class Code(Word):
    content: str


_match_memory_re = re.compile(r'([^ ]+) *\[ *(\w*?) *]')
_match_binary_operation_re = re.compile(r'(.*?) +([^ "]*?) +(.*) *')
_match_unary_operation_re = re.compile(r'(.*?) +(.*) *')
_match_sensor_re = re.compile(r'(@?\w+)\.(@?\w+)$')


def match_marco(s: str) -> Union[Macro, None]:
    lc_ind = s.find('(')
    if ')' not in s:
        return None
    if lc_ind == -1:
        return None

    obj_name = s[:lc_ind].split('.')
    if len(obj_name) == 1:
        macro_name = obj_name[0].strip()
        macro_obj = ''
    elif len(obj_name) == 2:
        macro_name = obj_name[1].strip()
        macro_obj = obj_name[0].strip()
    else:
        raise Exception(f"宏的名称解析错误：{s[:lc_ind]}")
    args_str = s[lc_ind + 1:-1].strip()

    args = []
    buf = ''
    instr = False
    is_code = False
    depth = 0
    for char in args_str:
        if char == '"':
            instr = not instr
            buf += char
            continue
        if instr:
            buf += char
            continue
        if char == '{':
            if depth > 0:
                buf += char
            depth += 1
            is_code = True
            continue
        if char == '}':
            if depth > 1:
                buf += char
            depth -= 1
            if depth < 0:
                raise Exception("解析错误，过多的 } 符号。")
            continue
        if depth > 0:
            buf += char
            continue

        if char == ',':
            if is_code:
                args.append(Code(buf.strip()))
                is_code = False
            else:
                args.append(buf.strip())
            buf = ''
            continue
        buf += char
        pass
    if depth != 0:
        raise Exception("存在不成对的 { 和 } 符号")
    if buf:
        if is_code:
            args.append(Code(buf.strip()))
        else:
            args.append(buf.strip())
        buf = ''
    return Macro(obj=macro_obj, name=macro_name, args=args)


def match_word(s: str) -> Union[Word, None]:
    s = s.strip()
    if s.startswith('"') and s.endswith('"'):
        return Value(s)
    if s.endswith(']') and s.count('[') == 1:
        m = _match_memory_re.match(s)
        return Memory(m.group(1), m.group(2))
    if s.startswith('{') and s.endswith('}'):
        return Code(s[1:-1])
    m = _match_sensor_re.match(s)
    if m:
        return Sensor(m.group(1), m.group(2))
    m = _match_binary_operation_re.match(s)
    if m:
        return BinaryOperation(name=m.group(2), left=m.group(1), right=m.group(3))
    m = _match_unary_operation_re.match(s)
    if m:
        return UnaryOperation(name=m.group(1), value=m.group(2))
    if s.endswith(')'):
        return match_marco(s)
    return Value(s)
